/*
 * =====================================================================================
 *
 *       Filename:  ListenSocketLinux.h
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  2012-10-01
 *       Revision:  none
 *       Compiler:  cmake & gcc
 *
 *         Author:  ankjt
 *
 * =====================================================================================
 */

#ifndef __LISTENSOCKET_H__
#define __LISTENSOCKET_H__

#include "SocketDefines.h"
#include "SocketMgrLinux.h"
#include "SocketOps.h"
#include "Thread.h"

template<class T>
class ListenSocket : public Thread
{
public:
    ListenSocket(int iSendBufferSize,int iRecvBufferSize)
    {
        m_iSendBufferSize = iSendBufferSize;
        m_iRecvBufferSize = iRecvBufferSize;
        m_pkMgr = NULL;
        m_bOpened = false;
    }

    ~ListenSocket()
    {
        printf("~ListenSocket [%d].");
        if(m_bOpened)
        {
            SocketOps::CloseSocket(m_sSocket);
        }
    }

    void SetSocketMgr(SocketMgr* pkMgr)
    {
        m_pkMgr = pkMgr;
    }
    bool StartListen(const char * pkListenAddress,int iPort)
    {
        m_bOpened = false;
        m_sSocket = socket(AF_INET, SOCK_STREAM, 0);
        SocketOps::ReuseAddr(m_sSocket);
       // SocketOps::Nonblocking(m_sSocket);

        m_kAddress.sin_family = AF_INET;
        m_kAddress.sin_port = ntohs((u_short)iPort);
        m_kAddress.sin_addr.s_addr = htonl(INADDR_ANY);

        if(strcmp(pkListenAddress, "0.0.0.0"))
        {
            struct hostent * hostname = gethostbyname(pkListenAddress);
            if(hostname != 0)
            {
                memcpy(&m_kAddress.sin_addr.s_addr, hostname->h_addr_list[0], hostname->h_length);
            }
        }

        int ret = ::bind(m_sSocket, (const sockaddr*)&m_kAddress, sizeof(m_kAddress));
        if(ret != 0)
        {
            printf("Bind unsuccessful on port %u.\n", (unsigned int)iPort);
            return false;
        }

        ret = listen(m_sSocket, 5);
        if(ret != 0) 
        {
            printf("Unable to listen on port %u.\n", (unsigned int)iPort);
            return false;
        }
        m_iLen = sizeof(sockaddr_in);
        //m_pkMgr->AddListenSocket(this);
        printf("StartListen port:[%d] [%llu].\n",iPort,this);
        m_bOpened = true;
        Start();
        return true;
    }

    void Close()
    {
        if(m_bOpened)
        {
            SocketOps::CloseSocket(m_sSocket);
        }
        m_bOpened = false;
    }

    bool IsOpen()
    {
        return m_bOpened;
    }
    void Run()
    {
          while(1)
          {
             OnAccept();
          }
    }
    void OnAccept()
    {
        m_aSocket = accept(m_sSocket,(sockaddr*)&m_kTempAddress,(socklen_t*)&m_iLen);
        if(m_aSocket == -1)
        {
            printf("Create OnAccept fail.\n");
            return;
        }
        printf("Create OnAccept.\n");
        m_kSocket = new T(m_aSocket,m_iSendBufferSize,m_iRecvBufferSize);
        m_kSocket->SetSocketMgr(m_pkMgr);
        m_kSocket->SetServerAddr(m_kAddress);
        m_kSocket->Accept(&m_kTempAddress);
    }

private:
    SOCKET m_sSocket;
    SOCKET m_aSocket;
    struct sockaddr_in m_kAddress;
    struct sockaddr_in m_kTempAddress;
    int    m_iLen;
    T *    m_kSocket;
    SocketMgr* m_pkMgr;

    int     m_iSendBufferSize;
    int     m_iRecvBufferSize;
    
    bool    m_bOpened;
  
};


#endif

